package com.mylib.libcore.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;

/**
 * @author
 * @time 2018-08-27 11:34
 */
public class DoubleUtil {

    //默认除法运算精度
    private static final int DEF_DIV_SCALE = 10;

    /**
     * 按照格式保留2位
     *
     * @param d double数
     * @return
     */
    public static String format(double d) {

        NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setMaximumFractionDigits(2);
        nf.setMinimumFractionDigits(2);

        //向上取整
        nf.setRoundingMode(RoundingMode.HALF_UP);
        /*
         * 如果想输出的格式用逗号隔开，可以设置成true
         */
        nf.setGroupingUsed(false);
        return nf.format(d);
    }


    /**
     * 格式化double, 小数点后保留num位
     *
     * @param arg0
     * @param num
     * @return
     */
    public static String doubleFormat(double arg0, Integer num) {
        NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setMaximumFractionDigits(num);
        nf.setMinimumFractionDigits(num);

        // 四舍五入
        nf.setRoundingMode(RoundingMode.HALF_UP);
        /*
         * 如果想输出的格式用逗号隔开，可以设置成true
         */
        nf.setGroupingUsed(false);
        return nf.format(arg0);
    }


    /**
     * 格式化double，没有小数点返回整数字符串，有小数点则保留num位
     *
     * @return
     */
    public static String doubleFormatMaxDigits(double arg0, Integer num) {
        BigDecimal bigDecimal = BigDecimal.valueOf(arg0);
        return doubleFormatMaxDigits(bigDecimal, num);
    }

    public static String doubleFormatMaxDigits(BigDecimal arg0, Integer num) {
        NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setMaximumFractionDigits(num);

        if (new BigDecimal(arg0.intValue()).compareTo(arg0) == 0) {
            nf.setMinimumFractionDigits(0);
        } else {
            nf.setMinimumFractionDigits(num);
        }

        // 四舍五入
        nf.setRoundingMode(RoundingMode.HALF_UP);
        /*
         * 如果想输出的格式用逗号隔开，可以设置成true
         */
        nf.setGroupingUsed(false);
        return nf.format(arg0);
    }


    /**
     * 提供精确的加法运算。
     *
     * @return 多个参数的和
     */
    public static double add(double... args) {
        BigDecimal b1 = new BigDecimal(0.0);
        if (args != null && args.length > 0) {
            for (double arg : args) {
                b1 = b1.add(new BigDecimal(Double.toString(arg)));
            }
        }
        return b1.doubleValue();
    }

    /**
     * 提供精确的减法运算。
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到
     * 小数点以后10位，以后的数字四舍五入。
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(double v1, double v2) {
        return div(v1, v2, DEF_DIV_SCALE);
    }

    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指
     * 定精度，以后的数字四舍五入。
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double div(double v1, double v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        if (v2 == 0) {
            return 0d;
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 提供精确的小数位四舍五入处理。
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 提供精确的类型转换(Float)
     *
     * @param v 需要被转换的数字
     * @return 返回转换结果
     */
    public static float convertsToFloat(double v) {
        BigDecimal b = new BigDecimal(v);
        return b.floatValue();
    }

    /**
     * 提供精确的类型转换(Int)不进行四舍五入
     *
     * @param v 需要被转换的数字
     * @return 返回转换结果
     */
    public static int convertsToInt(double v) {
        BigDecimal b = new BigDecimal(v);
        BigDecimal one = new BigDecimal("1");

        return b.divide(one, BigDecimal.ROUND_HALF_UP).intValue();
    }

    /**
     * 提供精确的类型转换(Long)
     *
     * @param v 需要被转换的数字
     * @return 返回转换结果
     */
    public static long convertsToLong(double v) {
        BigDecimal b = new BigDecimal(v);
        return b.longValue();
    }

    /**
     * 返回两个数中大的一个值
     *
     * @param v1 需要被对比的第一个数
     * @param v2 需要被对比的第二个数
     * @return 返回两个数中大的一个值
     */
    public static double returnMax(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.max(b2).doubleValue();
    }

    /**
     * 返回两个数中小的一个值
     *
     * @param v1 需要被对比的第一个数
     * @param v2 需要被对比的第二个数
     * @return 返回两个数中小的一个值
     */
    public static double returnMin(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.min(b2).doubleValue();
    }

    /**
     * 精确对比两个数字
     *
     * @param v1 需要被对比的第一个数
     * @param v2 需要被对比的第二个数
     * @return 如果两个数一样则返回0，如果第一个数比第二个数大则返回1，反之返回-1
     */
    public static int compareTo(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.compareTo(b2);
    }

    /**
     * 百分比格式化
     *
     * @param arg0
     * @param num
     * @return
     */
    public static String percentageFormat(double arg0, Integer num) {
        DecimalFormat df = new DecimalFormat("##.00%");
        if (num != null) {
            if (num == 1) {
                df = new DecimalFormat("####.0%");
            } else if (num == 2) {
                df = new DecimalFormat("####.00%");
            } else if (num == 3) {
                df = new DecimalFormat("####.000%");
            } else if (num == 4) {
                df = new DecimalFormat("####.0000%");
            }
        } else {
            df = new DecimalFormat("####%");
        }
        if (df.format(arg0).contains(".")) {
            if (df.format(arg0).substring(0, df.format(arg0).indexOf(".")).length() <= 0) {
                df = new DecimalFormat("0.00%");
                if (num != null) {
                    if (num == 1) {
                        df = new DecimalFormat("0.0%");
                    } else if (num == 2) {
                        df = new DecimalFormat("0.00%");
                    } else if (num == 3) {
                        df = new DecimalFormat("0.000%");
                    } else if (num == 4) {
                        df = new DecimalFormat("0.0000%");
                    }
                } else {
                    df = new DecimalFormat("0%");
                }
            }
        }
        return df.format(arg0);
    }

    /**
     * double每三位短号分割
     *
     * @param arg0
     * @param num
     * @return
     */
    public static String splitNumberFormat(double arg0, Integer num) {
        DecimalFormat df = new DecimalFormat("###,##0.00");
        if (num != null) {
            if (num == 1) {
                df = new DecimalFormat("###,##0.0");
            } else if (num == 2) {
                df = new DecimalFormat("###,##0.00");
            } else if (num == 3) {
                df = new DecimalFormat("###,##0.000");
            } else if (num == 4) {
                df = new DecimalFormat("###,##0.0000");
            }
        } else {
            df = new DecimalFormat("###,###");
        }
        return df.format(arg0);
    }

    /**
     * 解析字符串为double
     */
    public static double parse(String s) {
        double result = 0.0;
        try {
            result = Double.parseDouble(s);
        } catch (Exception ex) {

        }
        return result;
    }
}
